/*
 * Copyright 2009 Eat Local Food, LLC
 *
 * This file is part of gwtCommerce.
 *
 * gwtCommerce is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * gwtCommerce is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with gwtCommerce.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.elf.gwt.common.client;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;

import com.elf.gwt.common.client.components.CommonMultipleResultsComponent;
import com.elf.gwt.common.client.components.CommonSimpleComponent;
import com.elf.gwt.common.client.utils.CommonUtils;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.json.client.JSONParser;
import com.google.gwt.json.client.JSONValue;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.RootPanel;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public abstract class CommonComponentController implements EntryPoint
{	
	protected Label exceptionLabel = null;
	protected String[] alwaysAskHandles = {};
	protected HashMap<String, CommonSimpleComponent> componentHash;
	protected GWTCommerceCommonConstants commonConstants;
	protected String historyToken = "";
	protected boolean initializing = true;
	protected boolean loggedIn = false;

	protected CommonMultipleResultsComponent multipleResultsComponent;


	public static native String getInitialJSON()
	/*-{
	  return $wnd.initial_json;

	}-*/;

	public static native String enableWait()
	/*-{
	  for ( i = 0; i < $doc.styleSheets.length; i++ ) {
	      var href = $doc.styleSheets[i].href;
	      ln = href.length;
	      end = href.substring(ln-8);
	      if (end == 'Wait.css')
	      {
	          $doc.styleSheets[i].disabled = false;
	      }
	  }
	}-*/;

	public static native String disableWait()
	/*-{
	  for ( i = 0; i < $doc.styleSheets.length; i++ ) {
	      var href = $doc.styleSheets[i].href;
	      ln = href.length;
	      end = href.substring(ln-8);
	      if (end == 'Wait.css')
	      {
	          $doc.styleSheets[i].disabled = true;
	      }
	  }
	}-*/;

	public Panel getDisplayPanel() {
		return null;
	}

	/**
	 * This is the entry point method.
	 */
	public void onModuleLoad()
	{
		GWT.log("entering onModuleLoad");
		try {
			setInitializing(true);
			commonConstants = GWT.create(GWTCommerceCommonConstants.class);
			enableWait();
			History.addValueChangeHandler(new ValueChangeHandler<String>() {
				public void onValueChange(ValueChangeEvent<String> event) {
					String historyToken = event.getValue();
					updateFromHistory(historyToken);
				} 
			});

			componentHash = new HashMap<String, CommonSimpleComponent>();

			processOnModuleLoadBuildDisplayFramework();

			String initialString = getInitialJSON();
			JSONValue jsonInitialValue = JSONParser.parseLenient(initialString);

			String token = processOnModuleLoadParseMetaData(jsonInitialValue);
			GWT.log("token '" + token + "'");

			processOnModuleLoadParseDataPre();

			Set<String> handles = CommonUtils.getComponentHandles(jsonInitialValue);
			for (Iterator<String> iter = handles.iterator(); iter.hasNext(); )
			{
				String handle = iter.next();
				GWT.log("On Module Load - Handle: " + handle);
				CommonSimpleComponent component = getComponent(handle);
				if (component != null)
				{
					processOnModuleLoadParseDataGetComponentPost(component);
					multipleResultsComponent.addComponent(component);
				}
			}

			multipleResultsComponent.build(jsonInitialValue);

			processOnModuleLoadParseDataPost();

			String initToken = History.getToken();
			GWT.log("initToken '" + initToken + "'");
			if (initToken != null && initToken.length() > 0) {
				updateFromHistory(initToken);
			}
			else if (token != null && token.length() > 0) {
				History.newItem(token);
			}
			else {
				processOnModuleLoadDefaultDisplay();
			}

			RootPanel.get().add(getDisplayPanel());
			disableWait();
			Window.scrollTo(0, 0);
			setInitializing(false);
		}
		catch (Exception e)
		{
			e.printStackTrace();
			GWT.log("error in onModuleLoad " + e.getLocalizedMessage());
			exceptionLabel = new Label(e.getLocalizedMessage());
			RootPanel.get().add(exceptionLabel);			
		}

		GWT.log("exiting onModuleLoad");
	}

	public boolean isInitializing() {
		return initializing;
	}

	protected void setInitializing(boolean initializing) {
		this.initializing = initializing;
	}

	protected void processOnModuleLoadBuildDisplayFramework()
	{
	}

	protected String processOnModuleLoadParseMetaData(JSONValue jsonInitialValue)
	{
		String token = "";
		return token;
	}

	protected void processOnModuleLoadParseDataGetComponentPost(CommonSimpleComponent component)
	{
	}

	protected void processOnModuleLoadParseDataPre()
	{
	}

	protected void processOnModuleLoadParseDataPost()
	{
	}

	protected void processOnModuleLoadDefaultDisplay()
	{
	}

	protected void updateFromHistory(String historyToken)
	{
		GWT.log("updateFromHistory " + historyToken);
		if (exceptionLabel != null) exceptionLabel.setText("");
		this.historyToken = historyToken;
		// Parse the history token
		try
		{
			multipleResultsComponent.clearComponents();

			String[] alwayAsk = getAlwaysAskHandles();
			if (alwayAsk != null) {
				for (int i = 0; i < alwayAsk.length; i++)
				{
					CommonSimpleComponent alwaysAskComponent = getComponent(alwayAsk[i], false);
					if (alwaysAskComponent != null) multipleResultsComponent.addComponent(alwaysAskComponent);
				}
			}

			GWT.log("updateFromHistory AlwaysAskHandles added");
			
			String[] split = historyToken.split("--");
			String handle = split[0];
			GWT.log("updateFromHistory handle " + handle);
			CommonSimpleComponent component = getComponent(handle);
			if (component != null)
			{
				processUpdateFromHistoryBuildPre();
				GWT.log("updateFromHistory processUpdateFromHistoryBuildPre ");
				if (component.updateFromHistoryParameters(split))
				{
					GWT.log("updateFromHistory multipleResultsComponent.build() ");
					multipleResultsComponent.build();
					GWT.log("updateFromHistory after multipleResultsComponent.build() ");
				}
				else 
				{
					processUpdateFromHistoryBuildAbort();
				}
				GWT.log("updateFromHistory processUpdateFromHistoryBuildPost ");
				processUpdateFromHistoryBuildPost();
				GWT.log("updateFromHistory after processUpdateFromHistoryBuildPost ");
			}
			else
			{
				if (!getDisplayPanel().isVisible()) getDisplayPanel().setVisible(true);
				GWT.log("Unknown History", null);
			}
		}
		catch (Exception e)
		{
			if (!getDisplayPanel().isVisible()) getDisplayPanel().setVisible(true);
			GWT.log("History Error", e);
		}
	}

	protected void processUpdateFromHistoryBuildPre() 
	{
	}

	protected void processUpdateFromHistoryBuildAbort() 
	{
	}

	protected void processUpdateFromHistoryBuildPost() 
	{
	}

	public void hideComponents()
	{
	}

	public String getComponentTitle(String handle)
	{
		String title = handle;
		return title;
	}

	public void setComponent(CommonSimpleComponent component)
	{
		if (component != null) {
			componentHash.put(component.getHandle(), component);
			component.setVisible(false);
		}
	}

	public CommonSimpleComponent getComponent(String handle)
	{
		return getComponent(handle, true);
	}

	public CommonSimpleComponent getComponent(String handle, boolean create)
	{
		return null;
	}

	public GWTCommerceCommonConstants getCommonConstants() {
		return commonConstants;
	}

	public String getHistoryToken() {
		return historyToken;
	}

	protected void rebuild() {
		for (Iterator<String> iter = componentHash.keySet().iterator(); iter.hasNext(); )
		{
			String handle = iter.next();
			CommonSimpleComponent component = componentHash.get(handle);
			if (component.isVisible())
			{
				component.rebuild();
			}
		}
	}

	public void additionalRequestParameters(CommonSimpleComponent component)
	{
	}

	public CommonMultipleResultsComponent getMultipleResultsComponent() {
		return multipleResultsComponent;
	}

	public boolean isLoggedIn() {
		return loggedIn;
	}

	public void setLoggedIn(boolean loggedIn) {
		this.loggedIn = loggedIn;
	}

	public String[] getAlwaysAskHandles() {
		return alwaysAskHandles;
	}

	public void setAlwaysAskHandles(String[] alwaysAskHandles) {
		this.alwaysAskHandles = alwaysAskHandles;
	}
}
